/*-------------------------------------------------------------------------
 * CLR版本:     4.0.30319.42000
 * 创建人:      song
 * 创建时间：   2024/4/9 14:47:37
 * 功 能：     大小数
 *-------------------------------------------------------------------------*/

using System;
using UnityEngine;
using Random = UnityEngine.Random;

namespace SCore.UI
{
    [Serializable]
    public struct SMinMaxFloat
    {
        public float Min;
        public float Max;

        public SMinMaxFloat(float min, float max)
        {
            Min = min;
            Max = max;
        }
    }

    [Serializable]
    public struct SMinMaxInt
    {
        public int Min;
        public int Max;

        public SMinMaxInt(int min, int max)
        {
            Min = min;
            Max = max;
        }
    }

    public static class SMinMaxExtensions
    {
        #region IsInRange

        /// <summary>
        /// Value is in range of min and max
        /// </summary>
        public static bool IsInRange(this SMinMaxInt minMax, int value)
        {
            return value >= minMax.Min && value <= minMax.Max;
        }

        /// <summary>
        /// Value is in range of min and max
        /// </summary>
        public static bool IsInRange(this SMinMaxFloat minMax, float value)
        {
            return value >= minMax.Min && value <= minMax.Max;
        }

        #endregion

        #region Clamp

        /// <summary>
        /// Clamp value between MinMax values
        /// </summary>
        public static int Clamp(this SMinMaxInt minMax, int value)
        {
            return Mathf.Clamp(value, minMax.Min, minMax.Max);
        }

        /// <summary>
        /// Clamp value between MinMax values
        /// </summary>
        public static float Clamp(this SMinMaxFloat minMax, float value)
        {
            return Mathf.Clamp(value, minMax.Min, minMax.Max);
        }

        #endregion

        #region Length

        /// <summary>
        /// Distance from Min to Max
        /// </summary>
        public static int Length(this SMinMaxInt minMax)
        {
            return minMax.Max - minMax.Min;
        }

        /// <summary>
        /// Distance from Min to Max
        /// </summary>
        public static float Length(this SMinMaxFloat minMax)
        {
            return minMax.Max - minMax.Min;
        }

        #endregion

        #region MidPoint

        /// <summary>
        /// Point between Min and Max
        /// </summary>
        public static int MidPoint(this SMinMaxInt minMax)
        {
            return minMax.Min + minMax.Length() / 2;
        }

        /// <summary>
        /// Point between Min and Max
        /// </summary>
        public static float MidPoint(this SMinMaxFloat minMax)
        {
            return minMax.Min + minMax.Length() / 2f;
        }

        #endregion

        #region Lerp

        /// <summary>
        /// Lerp from Min to Max
        /// </summary>
        public static float Lerp(this SMinMaxInt minMax, float value)
        {
            return Mathf.Lerp(minMax.Min, minMax.Max, value);
        }

        /// <summary>
        /// Lerp from Min to Max
        /// </summary>
        public static float Lerp(this SMinMaxFloat minMax, float value)
        {
            return Mathf.Lerp(minMax.Min, minMax.Max, value);
        }

        /// <summary>
        /// Determines where a value lies between two points
        /// </summary>
        public static float InverseLerp(this SMinMaxInt minMax, float value)
        {
            return Mathf.InverseLerp(minMax.Min, minMax.Max, value);
        }

        /// <summary>
        /// Determines where a value lies between two points
        /// </summary>
        public static float InverseLerp(this SMinMaxFloat minMax, float value)
        {
            return Mathf.InverseLerp(minMax.Min, minMax.Max, value);
        }

        #endregion

        #region LerpUnclamped

        /// <summary>
        /// Lerp from Min to Max
        /// </summary>
        public static float LerpUnclamped(this SMinMaxInt minMax, float value)
        {
            return Mathf.LerpUnclamped(minMax.Min, minMax.Max, value);
        }

        /// <summary>
        /// Lerp from Min to Max
        /// </summary>
        public static float LerpUnclamped(this SMinMaxFloat minMax, float value)
        {
            return Mathf.LerpUnclamped(minMax.Min, minMax.Max, value);
        }

        #endregion

        #region RandomInRange

        /// <summary>
        /// Return a random int within [minInclusive..maxExclusive)
        /// </summary>
        public static int RandomInRange(this SMinMaxInt minMax)
        {
            return Random.Range(minMax.Min, minMax.Max);
        }

        /// <summary>
        /// Return a random int within [minInclusive..maxInclusive]
        /// </summary>
        public static float RandomInRange(this SMinMaxFloat minMax)
        {
            return Random.Range(minMax.Min, minMax.Max);
        }

        /// <summary>
        /// Return a random int within [minInclusive..maxInclusive]
        /// </summary>
        public static int RandomInRangeInclusive(this SMinMaxInt minMax)
        {
            return Random.Range(minMax.Min, minMax.Max + 1);
        }

        #endregion
    }
}

#if UNITY_EDITOR
namespace SCore.UI
{
    using UnityEditor;

    [CustomPropertyDrawer(typeof(SMinMaxInt), true)]
    public class MinMaxIntDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            EditorGUI.BeginProperty(position, label, property);
            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
            EditorGUI.indentLevel = 0; // PropertyDrawer Indent fix for nested inspectors

            var minProp = property.FindPropertyRelative("Min");
            var maxProp = property.FindPropertyRelative("Max");

            var minMaxLabel = "Min : Max";
            var labelWidth = 58;
            var spaceWidth = 4;
            var valWidth = (position.width / 2) - (labelWidth / 2f) - (spaceWidth * 4);

            position.width = valWidth;
            EditorGUI.PropertyField(position, minProp, GUIContent.none);

            position.x += valWidth + spaceWidth;
            position.width = labelWidth;
            EditorGUI.LabelField(position, minMaxLabel);

            position.x += labelWidth + spaceWidth;
            position.width = valWidth;
            EditorGUI.PropertyField(position, maxProp, GUIContent.none);

            if (GUI.changed)
            {
                if (maxProp.intValue < minProp.intValue) maxProp.intValue = minProp.intValue;

                property.serializedObject.ApplyModifiedProperties();
            }

            EditorGUI.EndProperty();
        }
    }


    [CustomPropertyDrawer(typeof(SMinMaxFloat), true)]
    public class MinMaxFloatDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            EditorGUI.BeginProperty(position, label, property);
            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
            EditorGUI.indentLevel = 0; // PropertyDrawer Indent fix for nested inspectors

            var minProp = property.FindPropertyRelative("Min");
            var maxProp = property.FindPropertyRelative("Max");

            var minMaxLabel = "Min : Max";
            var labelWidth = 58;
            var spaceWidth = 4;
            var valWidth = (position.width / 2) - (labelWidth / 2f) - (spaceWidth * 4);

            position.width = valWidth;
            EditorGUI.PropertyField(position, minProp, GUIContent.none);

            position.x += valWidth + spaceWidth;
            position.width = labelWidth;
            EditorGUI.LabelField(position, minMaxLabel);

            position.x += labelWidth + spaceWidth;
            position.width = valWidth;
            EditorGUI.PropertyField(position, maxProp, GUIContent.none);

            if (GUI.changed)
            {
                if (maxProp.floatValue < minProp.floatValue) maxProp.floatValue = minProp.floatValue;

                property.serializedObject.ApplyModifiedProperties();
            }

            EditorGUI.EndProperty();
        }
    }
}
#endif